package com.tcs.test.zk;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tcs.test.zk.base.BaseZookeeper;

public class ZkTest1 extends BaseZookeeper {

	private static final Logger logger = LoggerFactory.getLogger(ZkTest1.class);

	private final String ZK_PATH = "/java_client_test/c1";

	@Test
	public void create() {
		String data1 = "c1内容";
		logger.info("create : ZK_PATH {} , data : {} ", ZK_PATH, data1);
		// 4 建立节点 指定节点类型（不加withMode默认为持久类型节点）、路径、数据内容
		try {
			cf.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(ZK_PATH,
					data1.getBytes());
		} catch (Exception e) {
			logger.error("", e);
		}
	}
	
	public void create(String path , String data) {
		logger.info("create : path : {} , data : {} ", path, data);
		// 4 建立节点 指定节点类型（不加withMode默认为持久类型节点）、路径、数据内容
		try {
			cf.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path,
					data.getBytes());
		} catch (Exception e) {
			logger.error("", e);
		}
	}
	
	public void create(String path , String data , CreateMode createMode) {
		logger.info("create : path : {} , data : {} ", path, data);
		// 4 建立节点 指定节点类型（不加withMode默认为持久类型节点）、路径、数据内容
		try {
			cf.create().creatingParentsIfNeeded().withMode(createMode).forPath(path,
					data.getBytes());
		} catch (Exception e) {
			logger.error("", e);
		}
	}
	
	@Test
	public void delete() {
		logger.info("delete : ZK_PATH {} ", ZK_PATH);
		try {
			cf.delete().deletingChildrenIfNeeded().forPath(ZK_PATH);
		} catch (Exception e) {
			logger.error("", e);
		}
	}
	
	public void delete(String path) {
		logger.info("delete : path {} ", path);
		try {
			cf.delete().deletingChildrenIfNeeded().forPath(path);
		} catch (Exception e) {
			logger.error("", e);
		}
	}

	@Test
	public void get() {
		try {
			logger.info("path : {} ", new String(cf.getData().forPath(ZK_PATH)));
		} catch (Exception e) {
			logger.error("", e);
		}
	}

	@Test
	public void set() {
		try {
			this.get();
			cf.setData().forPath(ZK_PATH, "ads223322112".getBytes());
			this.get();
		} catch (Exception e) {
			logger.error("", e);
		}
	}
	
	public void set(String path , String data) {
		try {
			cf.setData().forPath(path, data.getBytes());
		} catch (Exception e) {
			logger.error("", e);
		}
	}

	/**
	 * 监控当前节点的数据状况：注意不会监控delete事件
	 * 
	 * @Title: watch1
	 */
	@Test
	public void watch1() {
		Object lock = new Object();
		// 4 建立一个cache缓存
		NodeCache cache = new NodeCache(cf, ZK_PATH, false);
		try {
			cache.start(true);
		} catch (Exception e) {
			logger.error("", e);
		}
		cache.getListenable().addListener(new NodeCacheListener() {
			/**
			 * <B>方法名称：</B>nodeChanged<BR>
			 * <B>概要说明：</B>触发事件为创建节点和更新节点，在删除节点的时候并不触发此操作。<BR>
			 * 
			 * @see org.apache.curator.framework.recipes.cache.NodeCacheListener#nodeChanged()
			 */
			@Override
			public void nodeChanged() throws Exception {
				logger.info("路径为：{} ", cache.getCurrentData().getPath());
				logger.info("数据为： {} ", new String(cache.getCurrentData().getData()));
				logger.info("状态为：{} ", cache.getCurrentData().getStat());
			}
		});
		this.set();
		synchronized (lock) {
			try {
				lock.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 * @Title: watch1
	 */
	@Test
	public void watch2() {
		this.create(ZK_PATH + "/wang", "" , CreateMode.EPHEMERAL);
		// 4 建立一个PathChildrenCache缓存,第三个参数为是否接受节点数据内容 如果为false则不接受
		PathChildrenCache cache = new PathChildrenCache(cf, ZK_PATH, true);
		
		ObjectMapper mapper = new ObjectMapper();
		
		// 5 在初始化的时候就进行缓存监听
		try {
			cache.start(StartMode.POST_INITIALIZED_EVENT);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		try {
			cache.getListenable().addListener(new PathChildrenCacheListener() {
				/**
				 * <B>方法名称：</B>监听子节点变更<BR>
				 * <B>概要说明：</B>新建、修改、删除<BR>
				 * 
				 * @see org.apache.curator.framework.recipes.cache.PathChildrenCacheListener#childEvent(org.apache.curator.framework.CuratorFramework,
				 *      org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent)
				 */
				@Override
				public void childEvent(CuratorFramework cf, PathChildrenCacheEvent event) throws Exception {
					switch (event.getType()) {
					case CHILD_ADDED:
						logger.info("CHILD_ADDED : {} " , event.getData().getPath());
						break;
					case CHILD_UPDATED:
						logger.info("CHILD_UPDATED : {} , data : {} " , event.getData().getPath() , new String(event.getData().getData(), "UTF-8"));
						break;
					case CHILD_REMOVED:
						logger.info("CHILD_REMOVED : {} " , event.getData().getPath());
						break;
					default:
						break;
					}
				}
			});
			Thread.sleep(3 * 1000L);
//			this.delete(ZK_PATH + "/wang");
//			this.create(ZK_PATH + "/wang", "wangbo1");
			this.set(ZK_PATH + "/wang" , "wango2");
			this.set(ZK_PATH + "/wang" , "wango3");
			this.set(ZK_PATH + "/wang" , "wango4");
			this.delete(ZK_PATH + "/wang");
			try {
				System.in.read();
			} catch (IOException e) {
				logger.error("", e);
			}
		} catch (Exception e) {
			logger.error("", e);
		} finally {
			CloseableUtils.closeQuietly(cache);
			CloseableUtils.closeQuietly(cf);
		}
	}
	
	public boolean existsNode(String path) {
		boolean result = false;
		try {
			Stat stat = cf.checkExists().forPath(path);
			logger.info(" stat : {} " , stat);
			result = stat == null ? false : true; 
		} catch (Exception e) {
			logger.error("" , e);
		}
		return result;
	}
	
	@Test
	public void test1() {
		String tempNode = ZK_PATH + "/wang";
		if (existsNode(tempNode)) {
			this.delete(tempNode);
		}
		this.create(tempNode, "node1");
		this.set(tempNode, "node2");
	}
	
	@Test
	public void test2() {
		InetAddress addr = null;
		try {
			addr = InetAddress.getLocalHost();
		} catch (UnknownHostException e) {
			logger.error("" , e);
		}
		String ip = addr.getHostAddress().toString();
		logger.info("ip : {} " , ip);
	}
}
